//
//  BluFiTool.swift
//  ZhiTing
//
//  Created by iMac on 2021/9/27.
//

import Foundation
import ESPProvision
import Combine

class BluFiTool: NSObject, DeviceProvisionRegisterable {

    /// 当前注册设备步骤状态
    var currentRegisterDeviceState: RegisterDeviceState = .origin

    /// 用于局域网扫描设备
    var udpDeviceTool: UDPDeviceTool?

    var cancellables = Set<AnyCancellable>()
    
    /// 连接的设备
    var currentDevice: ESPPeripheral?

    /// blufi client
    var blufiClient: BlufiClient?
    
    
    /// 用于扫描Blufi设备
    let bluFiHelper = ESPFBYBLEHelper.share()
    
    /// 已发现的设备
    var discoveredDevices = [ESPPeripheral]()
    
    /// 已发现设备的配网状态 (设备uuid: 设备id)
    var devicesProvisionStates = [String: String]()
    
    /// 扫描Blufi时过滤关键词
    var filterContent = "MH-"
    
    /// 连接设备回调
    var connectCallback: ((Bool) -> Void)?
    
    /// 配网结果回调
    var provisionCallback: ((Bool) -> Void)?
    
    /// 注册设备回调 (注册设备结果, 错误信息, 错误码, 设备id, 控制页路径)
    var registerDeviceCallback: ((_ success: Bool, _ error: String?, _ error_code: Int?, _ device_id: Int?, _ control: String?) -> Void)?
    
    /// 是否多设备配网
    var isMultipleProvisioning = false
    
    /// 置网成功flag
    var provisionFlag = false
    
    /// 硬件设备ID
    var deviceID = ""
    
    deinit {
        debugPrint("BlufiTool deinit.")
    }

    
    /// 搜索发现的设备(用于配网成功后 调用添加设备接口)
    var discoverDeviceModel: DiscoverDeviceModel?

    /// 连接设备Blufi设备
    func connect(device: ESPPeripheral) {
        self.currentRegisterDeviceState = .origin
        self.currentDevice = device
        blufiClient?.close()
        blufiClient = BlufiClient()
        blufiClient?.centralManagerDelete = self
        blufiClient?.peripheralDelegate = self
        blufiClient?.blufiDelegate = self
        blufiClient?.connect(device.uuid.uuidString)
    }
    
    /// 通过uuid连接已发现设备
    func connectByUUID(uuid: String) {
        if discoveredDevices.count > 1 {
            isMultipleProvisioning = true
        }
        
        
        if let d = self.discoveredDevices.first(where: { $0.uuid.uuidString == uuid }) {
            self.currentRegisterDeviceState = .origin
            self.currentDevice = d
            ZTConsole.log("连接蓝牙设备: \(d.uuid.uuidString)")
            /// 多设备配网下,如果之前已经配网成功了直接回调成功
            if let did = devicesProvisionStates[uuid] {
                deviceID = did
                provisionFlag = true
                connectCallback?(true)
                return
            }
            

            blufiClient?.close()
            blufiClient = BlufiClient()
            blufiClient?.centralManagerDelete = self
            blufiClient?.peripheralDelegate = self
            blufiClient?.blufiDelegate = self
            blufiClient?.connect(d.uuid.uuidString)
        }
    }

    
    /// 发送配网信息
    /// - Parameters:
    ///   - ssid: wifi名称
    ///   - pwd: wifi密码
    func configWifi(ssid: String, pwd: String) {
        
        /// 多设备配网下,如果之前已经配网成功了直接回调成功
        if let uuid = currentDevice?.uuid.uuidString, let did = devicesProvisionStates[uuid] {
            deviceID = did
            provisionFlag = true
            provisionCallback?(true)
            return
        }

        self.provisionFlag = false
        let params = BlufiConfigureParams()
        params.opMode = OpModeSta
        params.staSsid = ssid
        params.staPassword = pwd
        blufiClient?.configure(params)
    }

    /// 扫描blufi蓝牙设备
    /// - Parameters:
    ///   - filterContent: 过滤关键词
    ///   - callback: 发现设备回调
    func scanBlufiDevices(filterContent: String = "BLUFI", callback: (([ESPPeripheral]) -> Void)?) {
        currentRegisterDeviceState = .origin
        self.filterContent = filterContent
        devicesProvisionStates.removeAll()
        discoveredDevices.removeAll()
        blufiClient?.close()
        blufiClient = BlufiClient()
        blufiClient?.centralManagerDelete = self
        blufiClient?.peripheralDelegate = self
        blufiClient?.blufiDelegate = self
        
        bluFiHelper.startScan { [weak self] blufiDevice in
            guard let self = self else { return }
            if self.shouldAddToSource(device: blufiDevice) {
                self.discoveredDevices.append(blufiDevice)
            }
        }
        
        
        
        DispatchQueue.main.asyncAfter(deadline: .now() + 10) { [weak self] in
            guard let self = self else { return }
            self.bluFiHelper.stopScan()
            callback?(self.discoveredDevices)
        }

    }
    
    /// 扫描并连接设备
    /// - Parameter filterContent: 过滤关键词
    func scanAndConnectDevice(filterContent: String = "BLUFI") {
        currentRegisterDeviceState = .origin
        self.filterContent = filterContent
        discoveredDevices.removeAll()
        
        bluFiHelper.startScan { [weak self] blufiDevice in
            guard let self = self else { return }
            if self.shouldAddToSource(device: blufiDevice) {
                self.stopScanDevices()
                self.currentDevice = blufiDevice
                self.connect(device: blufiDevice)
            }
        }
        
        DispatchQueue.main.asyncAfter(deadline: .now() + 15) { [weak self] in
            guard let self = self else { return }
            if self.currentDevice == nil {
                self.stopScanDevices()
                self.connectCallback?(false)
            }
            
        }

    }

    
    /// 停止扫描blufi蓝牙设备
    func stopScanDevices() {
        bluFiHelper.stopScan()
    }

    /// 判断是否应该将发现的设备添加至发现列表
    /// - Parameter device: 待添加设备
    /// - Returns: 是否添加
    func shouldAddToSource(device: ESPPeripheral) -> Bool {
        if filterContent.count > 0 {
            if device.name.isEmpty || !device.name.hasPrefix(filterContent) {
                return false
            }
        }
        /// 已存在
        if discoveredDevices.contains(where: { $0.uuid == device.uuid }) {
            return false
        }
        return true
    }

}



extension BluFiTool: CBCentralManagerDelegate, CBPeripheralDelegate, BlufiDelegate {
    // MARK: - CBCentralManagerDelegate
    func centralManagerDidUpdateState(_ central: CBCentralManager) {
        
    }
    
    func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
        ZTConsole.log("Blufi连接成功")
        provisionFlag = false
        connectCallback?(true)
    }
    
    func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) {
        ZTConsole.log("Blufi连接失败")
        connectCallback?(false)
    }
    
    func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
        ZTConsole.log("Blufi连接断开")
        if !provisionFlag && peripheral.identifier.uuidString == currentDevice?.uuid.uuidString {
            connectCallback?(false)
        }
        
    }


    // MARK: - BlufiDelegate
    
    func blufi(_ client: BlufiClient, gattPrepared status: BlufiStatusCode, service: CBService?, writeChar: CBCharacteristic?, notifyChar: CBCharacteristic?) {
        ZTConsole.log("Blufi准备就绪")
    }
    
    func blufi(_ client: BlufiClient, didNegotiateSecurity status: BlufiStatusCode) {
        ZTConsole.log("Blufi安全校验成功")
    }
    
    func blufi(_ client: BlufiClient, didPostConfigureParams status: BlufiStatusCode) {
        ZTConsole.log("Blufi已将发送配网信息至设备")
    }
    
    func blufi(_ client: BlufiClient, didReceiveDeviceStatusResponse response: BlufiStatusResponse?, status: BlufiStatusCode) {
        ZTConsole.log("Blufi接受到设备响应")
        if status == StatusSuccess {
            if let isConnect = response?.isStaConnectWiFi(), isConnect == true {
                ZTConsole.log("Blufi置网成功")
                DispatchQueue.main.asyncAfter(deadline: .now() + 1) { [weak self] in
                    guard let self = self else { return }
                    self.provisionCallback?(true)
                }
                
            } else {
                ZTConsole.log("Blufi置网失败")
                provisionCallback?(false)
            }
            
        } else {
            ZTConsole.log("Blufi置网失败")
            provisionCallback?(false)
        }
    }
    
    func blufi(_ client: BlufiClient, didReceiveCustomData data: Data, status: BlufiStatusCode) {
        ZTConsole.log("Blufi接受到设备自定义响应")
        /// 设备ID
        guard let deviceID = String(data: data, encoding: .utf8) else { return }
        provisionFlag = true
        self.deviceID = deviceID.lowercased()
        ZTConsole.log("设备id: \(self.deviceID )")
        
        if let uuid = currentDevice?.uuid.uuidString { /// 记录该设备已经配网成功
            devicesProvisionStates[uuid] = deviceID.lowercased()
        }
        
        
        
    }

    func blufi(_ client: BlufiClient, didPostCustomData data: Data, status: BlufiStatusCode) {
        ZTConsole.log("Blufi已将自定义信息发送至设备")
    }
    
    func blufi(_ client: BlufiClient, didReceiveError errCode: Int) {
        ZTConsole.log("Blufi接受到错误 \(errCode)")
        provisionCallback?(false)
    }
    
    
}
